/**
 * @(#)com.epgis.communication.util.ByteUtils
 *
 * 版权声明 厦门亿力吉奥信息科技有限公司 版权所有,违者必究

 * <br> Copyright：Copyright (c)  2012 
 * <br> Company: 厦门亿力吉奥信息科技有限公司 
 * <br> Author: 林开雄
 * <br>  Date：12-10-25
 * <br> Version： 1.0
 *————————————————————————————————————
 * 修改记录
 *    修改者：
 *    修改时间：
 *    修改原因：
 *—————————————————————————————————————
 */
package com.huayi.datagovernance.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author 林开雄
 * @version 1.0
 *          功能说明： 字节操作控制工具类
 */
@Slf4j
public class ByteUtils {

    /**
     * Integer转Byte[]
     *
     * @param number
     * @return
     */
    public static byte[] intToByte(int number) {
        int temp = number;
        byte[] b = new byte[4];
        for (int i = 0; i < b.length; i++) {
            b[i] = new Integer(temp & 0xff).byteValue();
            temp = temp >> 8;
        }
        return b;
    }

    /**
     * Byte[]转Integer
     *
     * @param intByte
     * @return
     */
    public static int byteToInt(byte[] intByte) {
        int fromByte = 0;
        for (int i = 0; i < 4; i++) {
            int n = (intByte[i] < 0 ? (int) intByte[i] + 256 : (int) intByte[i]) << (8 * i);
            fromByte += n;
        }
        return fromByte;
    }


    /**
     * Short转Byte[]
     *
     * @param number
     * @return
     */
    public static byte[] shortToByte(short number) {
        int temp = number;
        byte[] b = new byte[2];
        for (int i = 0; i < b.length; i++) {
            b[i] = new Integer(temp & 0xff).byteValue();
            temp = temp >> 8;
        }
        return b;
    }


    /**
     * Byte[]转Short
     *
     * @param intByte
     * @return
     */
    public static int byteToShort(byte[] shortByte) {
        int fromByte = 0;
        for (int i = 0; i < 2; i++) {
            int n = (shortByte[i] < 0 ? (short) shortByte[i] + 256 : (short) shortByte[i]) << (8 * i);
            fromByte += n;
        }
        return fromByte;
    }

    /**
     * Double转Byte[]
     *
     * @param d
     * @return
     */
    public static byte[] doubleToByte(double d) {
        byte[] b = new byte[8];
        long l = Double.doubleToLongBits(d);
        for (int i = 0; i < b.length; i++) {
            b[i] = new Long(l).byteValue();
            l = l >> 8;
        }
        return b;
    }

    /**
     * Byte[]转Double
     *
     * @param b
     * @return
     */
    public static double byteToDouble(byte[] b) {
        long l;
        l = b[0];
        l &= 0xff;
        l |= ((long) b[1] << 8);
        l &= 0xffff;
        l |= ((long) b[2] << 16);
        l &= 0xffffff;
        l |= ((long) b[3] << 24);
        l &= 0xffffffffl;
        l |= ((long) b[4] << 32);
        l &= 0xffffffffffl;
        l |= ((long) b[5] << 40);
        l &= 0xffffffffffffl;
        l |= ((long) b[6] << 48);
        l &= 0xffffffffffffffl;
        l |= ((long) b[7] << 56);
        return Double.longBitsToDouble(l);
    }

    /**
     * Long转Byte[]
     *
     * @param num
     * @return
     */
    public static byte[] longToByte(long num) {
        byte[] b = new byte[8];
        long l = num;
        for (int i = 0; i < b.length; i++) {
            b[i] = new Long(l).byteValue();
            l = l >> 8;
        }
        return b;
    }

    /**
     * Byte[]转Long
     *
     * @param b
     * @return
     */
    public static long byteToLong(byte[] b) {
        long l;
        l = b[0];
        l &= 0xff;
        l |= ((long) b[1] << 8);
        l &= 0xffff;
        l |= ((long) b[2] << 16);
        l &= 0xffffff;
        l |= ((long) b[3] << 24);
        l &= 0xffffffffl;
        l |= ((long) b[4] << 32);
        l &= 0xffffffffffl;
        l |= ((long) b[5] << 40);
        l &= 0xffffffffffffl;
        l |= ((long) b[6] << 48);
        l &= 0xffffffffffffffl;
        l |= ((long) b[7] << 56);
        return l;
    }

    /**
     * Byte[]转String
     *
     * @param b
     * @param charsetName "GBK"
     * @return
     */
    public static String byteToString(byte[] b, String charsetName) {
        String str = null;
        try {
            if(StringUtils.isEmpty(charsetName)){
                charsetName = "GBK";
            }
            str = new String(b, charsetName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

    /**
     * Byte[]转String
     *
     * @param b
     * @param charsetName "GB2312"
     * @return
     */
    public static String byteToString(byte[] b) {
        return byteToString(b, "GBK");
    }

    /**
     * String转Byte[]
     *
     * @param b
     * @return
     */
    public static byte[] stringToByte(String s) {
        byte[] bytes = stringToByte(s,"GBK"); //// 数据代理使用GBK编码方式获取值
        return bytes;
    }

    /**
     * String转Byte[]
     *
     * @param b
     * @return
     */
    public static byte[] stringToByte(String s, String charsetName) {
        byte[] bytes = null;
        try {
            if(StringUtils.isEmpty(charsetName)){
                charsetName = "GBK";//数据代理使用GBK编码方式获取值
            }
            bytes = s.getBytes(charsetName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bytes;
    }

    /**
     * Blob转成byte数组
     *
     * @param blob
     * @return
     */
    public static byte[] blobToBytes(Blob blob) {
        byte[] b = null;
        try {
            b = blob.getBytes(1L, (int) blob.length());
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return b;
    }

    /**
     * Clob转成byte数组
     *
     * @param clob
     * @param charsetName
     * @return
     */
    public static byte[] clobToBytes(Clob clob, String charsetName) {
        byte[] b = null;
        try {
            if(clob==null) return null;
            String retVal = (clob != null ? clob.getSubString(1, (int) clob.length()) : null);
            if(StringUtils.isEmpty(retVal)){
                return null;
            }
            b = retVal.getBytes(StringUtils.isEmpty(charsetName)?"GBK":charsetName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return b;
    }

    /**
     * Clob转成byte数组
     *
     * @param clob
     * @return
     */
    public static byte[] clobToBytes(Clob clob) {
      return clobToBytes(clob,"GBK") ;
    }

    /**
     * 十六进制字符串转成byte数组
     *
     * @param hex
     * @return
     */
    public static byte[] hexStringToByte(String hex) {
        byte[] baKeyword = new byte[hex.length() / 2];
        for (int i = 0; i < baKeyword.length; i++) {
            try {
                baKeyword[i] = (byte) (Integer.parseInt(hex.substring(i * 2, i * 2 + 2), 16));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return baKeyword;
    }

    /**
     * 字节数组转换为十六进制字符串
     *
     * @param hex
     * @return
     */
    public static String byteToHexString(byte[] b) {
        int len = b.length;
        String ret = "0x ";
        for (int i = 0; i < len; i++) {
            int a = (int) b[i];
            if (a < 0) a += 256;
            String s = Integer.toHexString(a);
            if (s.length() == 1) {
                s = "0" + s;
            }
            ret += s + " ";
        }
        return ret;
    }

    /**
     * 将指定的目标数组追加到原数组后面，返回一个新数组
     *
     * @param src  - 源数组。
     * @param dest - 目标数组。
     * @return
     */
    public static byte[] append(byte[] src, byte[] dest) {
        byte[] result = new byte[src.length + dest.length];
        System.arraycopy(src, 0, result, 0, src.length);
        System.arraycopy(dest, 0, result, src.length, dest.length);
        return result;
    }


    /**
     * 将指定的目标追加到原数组后面，返回一个新数组
     *
     * @param src  - 源数组。
     * @param dest - 目标。
     * @return
     */
    public static byte[] append(byte[] src, byte dest) {
        byte[] _result = new byte[src.length + 1];
        byte[] _dest = new byte[1];
        _dest[0] = dest;
        System.arraycopy(src, 0, _result, 0, src.length);
        System.arraycopy(_dest, 0, _result, src.length, _dest.length);
        return _result;
    }

    /**
     * 从输入流中读取到字节数组中
     * @param in           输入流
     * @param length       读取长度
     * @return
     * @throws IOException
     */
    public static byte[] readBytes(InputStream in, long length) throws IOException {
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int read = 0;
        while (read < length) {
            int cur = in.read(buffer, 0, (int) Math.min(1024, length - read));
            if (cur < 0) {
                break;
            }
            read += cur;
            bo.write(buffer, 0, cur);
        }
        return bo.toByteArray();
    }



    /**
     * 按字节长度截取字符串
     *
     * @param orgin       需要截取的字符串
     * @param blength     需要保留的字节长度
     * @param charsetName 编码,对于字符集为UTF-8的数据库,请指定编码为UTF-8;字符集为GBK的数据库,请指定编码GBK
     * @return 截取后的字符串
     * @throws UnsupportedEncodingException 不支持的字符编码
     */
    public static String subString4Byte(String orgin, int blength, String charsetName) {
        return subStringb2(orgin, blength, charsetName).get(0);
    }

    /**
     * @Auther: liuzujie
     * @Date: 2020/1/16 18:19
     * @Desc: 获取字符串字节数
     * @param: orgin（字符串）charsetName（字符集）
     */
    public static final int getStringByteLength(String orgin, String charsetName) {
        byte[] bs = new byte[0];
        try {
            bs = orgin.getBytes(charsetName);
        } catch (UnsupportedEncodingException e) {
            log.error("获取字符串字节数异常,orgin:{},charsetName:{},info:", orgin, charsetName, e);
        }
        return bs.length;
    }

    private static List<String> subStringb2(String orgin, int blength, String charsetName) {
        List<String> result = new ArrayList<>();
        int length;
        byte[] bs = new byte[0];
        try {
            bs = orgin.getBytes(charsetName);
            while (bs.length > 0) {
                length = blength;
                if (length >= bs.length) {
                    result.add(new String(bs, 0, bs.length, charsetName));
                    break;
                }
                if ("UTF8".equals(charsetName.toUpperCase()) || "UTF-8".equals(charsetName.toUpperCase())) {
                    while (length > 0) {
                        if ((bs[length] | 0x7F) == 0x7F) {
                            break;
                        }
                        if ((bs[length] & 0xC0) == 0xC0) {
                            break;
                        }
                        length--;
                    }
                } else if ("GBK".equals(charsetName.toUpperCase())) {
                    boolean removLast = length % 2 == 1;
                    for (int i = 0; i < length; i++) {
                        if ((bs[i] | 0x7F) == 0x7F) {
                            removLast = !removLast;
                        }
                    }
                    if (removLast) {
                        length--;
                    }
                } else if ("UNICODE".equals(charsetName.toUpperCase())) {
                    if (length % 2 == 1) {
                        length--;
                    }
                } else if ("UTF-16".equals(charsetName.toUpperCase()) || "UTF16".equals(charsetName.toUpperCase())) {
                    if (length % 2 == 1) {
                        length--;
                    }
                } else if ("UTF-16BE".equals(charsetName.toUpperCase())) {
                    if (length % 2 == 1) {
                        length--;
                    }
                } else if ("UTF-16LE".equals(charsetName.toUpperCase())) {
                    if (length % 2 == 1) {
                        length--;
                    }
                }
                result.add(new String(bs, 0, length, charsetName));
                bs = Arrays.copyOfRange(bs, length, bs.length);
            }
            if (result.size() == 0) {
                result.add("");
            }
        } catch (UnsupportedEncodingException e) {
            log.error("按字节长度分割字符串异常,orgin:{},blength:{},charsetName:{},info:", orgin, blength, charsetName, e);
        }
        return result;
    }

    public static void main(String[] args) {
        String str = "和滨二线D0121B022配变1线2号2支5号杆 - 10kV滨古线1013线路155号1线13+1号1支6号杆D0213B022配变-杆塔-杆塔-导线";
        System.out.println(subString4Byte(str, 100, "GBK"));
        System.out.println(getStringByteLength(str, "GBK"));
    }
    }
